home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 4 / BBS in a Box - Macintosh - Volume IV (January 1992) (BBS in a Box).iso / Files / Prog / N-P / ProtoClip.sea / proto.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-21  |  20.2 KB  |  958 lines  |  [TEXT/KAHL]

  1. /*
  2.     proto.c
  3.     
  4.     converted to Mac FKEY by Alex D. Chaffee (adc)
  5.     (chaffee@reed.bitnet, AOL:AlexCh, CIS:71210,1117)
  6.     Copyright © 1991 Alex Chaffee. Permission granted to change and 
  7.     distribute freely, provided all changes are documented.
  8.     
  9.     Version History:
  10.         
  11.         1.0    3/1/91    Converted mkptypes.c
  12.         
  13.         1.1    3/9/91    Works with Think C methods and (presumably) C++
  14. */
  15.  
  16. /*    mkptypes.c comments:    */
  17. /*
  18.  *    Program to extract function declarations from C source code
  19.  *
  20.  *    Written by Eric R. Smith (ersmith@uwovax.uwo.ca or @uwovax.bitnet) 
  21.  *        and placed in the public domain
  22.  *    Thanks to:
  23.  *        Jwahar R. Bammi, for catching several bugs and providing the Unix makefiles
  24.  *        Byron T. Jenings Jr. for cleaning up the space code, providing a Unix
  25.  *            manual page, and some ANSI and C++ improvements.
  26.  *        Skip Gilbrech for code to skip parameter names in prototypes.
  27.  *        ... and many others for helpful comments and suggestions.
  28.  */
  29.  
  30. /* 
  31.     UNIX command-line options - compiled in.
  32.     To effect any of these options, either comment or uncomment the 
  33.     #defines and recompile. Some of them have not been fully tested,
  34.     so be careful.
  35. */
  36.  
  37. /*    #define opt_e        /**/
  38. /*  The -e option causes the "extern" keyword to be explicitly printed for
  39.     external functions. Some non-ANSI compilers may need this.
  40. */
  41.  
  42. /*    #define opt_n        /**/
  43. /*  The -n option causes the line number where each function was defined to
  44.     be prepended to the prototype declaration as a comment.
  45. */
  46.  
  47.     #define macro_name_string    "_P"
  48. /*    This option controls the name of the macro used to guard prototype
  49.     definitions. Normally this is "_P", but you can change it to any string 
  50.     you like. To eliminate the guard macro entirely, use the -A option.
  51.     (Formerly -p option -adc)
  52. */
  53.  
  54.     #define opt_s    /**/
  55. /*  The -s option causes prototypes to be generated for functions declared
  56.     "static" as well as extern functions.
  57. */
  58.  
  59. /*    #define opt_x    /**/
  60. /*  The -x option causes parameter names to be omitted from the output proto-
  61.     types. This may be necessary for some brain-damaged pseudo-ANSI com-
  62.     pilers. You may also prefer this style of output. This option has not been
  63.     thoroughly tested.
  64. */
  65.  
  66. /*    #define opt_z    /**/
  67. /*  The -z option suppresses the definition of the prototype macro given by -p.
  68.     Header files generated by mkptypes with this option will not work unless
  69.     the prototype macro has been defined elsewhere in the program by the user.
  70.     Used with the -p option, the -z option allows use of predefined prototype
  71.     hiding macros that may exist on some systems.
  72. */
  73.  
  74.     #define opt_A    /**/
  75. /*  The -A option causes the prototypes emitted to be only readable by ANSI
  76.     compilers.  Normally, the prototypes are "macro-ized" so that compilers
  77.     with __STDC__not defined don't see them.
  78. */
  79.  
  80.     #define opt_C    /**/
  81. /*    This option causes Think C class names to be placed in comments following
  82.     the method prototype. e.g.
  83.         void amethodname(int x);    /* aclassname * /
  84.     -adc
  85. */
  86.  
  87. /*    #define opt_H    /**/
  88. /*    This option prints a header ("/* Prototypes * /") at the top of the 
  89.     prototype list    -adc
  90. */
  91.  
  92. #include <stddef.h>
  93. #include <stdlib.h>
  94.  
  95. #ifndef EXIT_SUCCESS
  96. #define EXIT_SUCCESS  0
  97. #define EXIT_FAILURE  1
  98. #endif
  99.  
  100. #include <stdio.h>
  101. #include <ctype.h>
  102. #include <string.h>
  103.  
  104. #include "config.h"
  105. #include "hfile.h"
  106. #include "proto.h"
  107.  
  108. /*#define DEBUG(s) (fputs(s, stderr)) /* */
  109. #define DEBUG(s) /* */
  110.  
  111. #define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
  112. #define ABORTED ( (Word *) -1 )
  113. #define MAXPARAM 20         /* max. number of parameters to a function */
  114. #define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
  115.  
  116. int dostatic = 0;        /* do static functions? */
  117. int donum    = 0;        /* print line numbers? */
  118. int define_macro   = 1;        /* define macro for prototypes? */
  119. int use_macro   = 1;        /* use a macro for prototypes? */
  120. char macro_name[sizeof(macro_name_string)+1];        /*   macro to use for prototypes */
  121. int no_parm_names = 0;        /* no parm names - only types */
  122. int print_extern = 0;        /* use "extern" before function declarations */
  123. #ifdef CPP
  124. int call_cpp = 0;        /* preprocess files */
  125. #endif
  126. int print_class = 0;    /*    show class name        -adc */
  127.  
  128. int inquote = 0;        /* in a quote?? */
  129. int newline_seen = 1;        /* are we at the start of a line */
  130. long linenum  = 1L;        /* line number in current file */
  131. int glastc   = ' ';        /* last char. seen by getsym() */
  132.  
  133. static char *typewords[15];
  134.  
  135. typedef struct word {
  136.     struct word *next;
  137.     char   string[1];
  138. } Word;
  139.  
  140.  
  141. /*    Local Prototypes    */
  142. #pragma mark prototypes
  143. Word *word_alloc(char *s);
  144. void word_free(Word *w);
  145. int List_len(Word *w);
  146. Word *word_append(Word *w1, Word *w2);
  147. int foundin(Word *w1, Word *w2);
  148. void addword(Word *w, char *s);
  149. void typefixhack(Word *w);
  150. int ngetc(HFILE *h);
  151. int hnextch(HFILE *h);
  152. int nextch(HFILE *h);
  153. int getsym(char *buf, HFILE *h);
  154. int skipit(char *buf, HFILE *h);
  155. int is_type_word(char *s);
  156. Word *typelist(Word *p);
  157. Word *getparamlist(HFILE *h);
  158. void emit(HFILE *hOut, Word *wlist, Word *plist, long startline);
  159. void getdecl(HFILE *h, HFILE *hOut);
  160. void buildtypewords(void);
  161.  
  162. /*
  163.  * Routines for manipulating lists of words.
  164.  */
  165.  
  166. Word *word_alloc(s)
  167.     char *s;
  168. {
  169.     Word *w;
  170.  
  171. /* note that sizeof(Word) already contains space for a terminating null
  172.  * however, we add 1 so that typefixhack can promote "float" to "double"
  173.  *  by just doing a strcpy.
  174.  */
  175.     w = (Word *) malloc(sizeof(Word) + strlen(s) + 1);
  176.     strcpy(w->string, s);
  177.     w->next = NULL;
  178.     return w;
  179. }
  180.  
  181. void word_free(w)
  182.     Word *w;
  183. {
  184.     Word *oldw;
  185.     while (w) {
  186.         oldw = w;
  187.         w = w->next;
  188.         free(oldw);
  189.     }
  190. }
  191.  
  192. /* return the length of a list; empty words are not counted */
  193. int
  194. List_len(w)
  195.     Word *w;
  196. {
  197.     int count = 0;
  198.  
  199.     while (w) {
  200.         if (*w->string) count++;
  201.         w = w->next;
  202.     }
  203.     return count;
  204. }
  205.  
  206. /* Append two lists, and return the result */
  207.  
  208. Word *word_append(w1, w2)
  209.     Word *w1, *w2;
  210. {
  211.     Word *r, *w;
  212.  
  213.     r = w = word_alloc("");
  214.  
  215.     while (w1) {
  216.         w->next = word_alloc(w1->string);
  217.         w = w->next;
  218.         w1 = w1->next;
  219.     }
  220.     while (w2) {
  221.         w->next = word_alloc(w2->string);
  222.         w = w->next;
  223.         w2 = w2->next;
  224.     }
  225.  
  226.     return r;
  227. }
  228.     
  229. /* see if the last entry in w2 is in w1 */
  230.  
  231. int
  232. foundin(w1, w2)
  233.     Word *w1, *w2;
  234. {
  235.     while (w2->next)
  236.         w2 = w2->next;
  237.  
  238.     while (w1) {
  239.         if (!strcmp(w1->string, w2->string))
  240.             return 1;
  241.         w1 = w1->next;
  242.     }
  243.     return 0;
  244. }
  245.  
  246. /* add the string s to the given list of words */
  247.  
  248. void addword(w, s)
  249.     Word *w; char *s;
  250. {
  251.     while (w->next) w = w->next;
  252.     w->next = word_alloc(s);
  253. }
  254.  
  255. /* typefixhack: promote formal parameters of type "char", "unsigned char",
  256.    "short", or "unsigned short" to "int".
  257. */
  258.  
  259. void typefixhack(w)
  260.     Word *w;
  261. {
  262.     Word *oldw = 0;
  263.  
  264.     while (w) {
  265.         if (*w->string) {
  266.             if ( (!strcmp(w->string, "char") ||
  267.                   !strcmp(w->string, "short") )
  268.                 && (List_len(w->next) < 2) )
  269.             {
  270. /* delete any "unsigned" specifier present -- yes, it's supposed to do this */
  271.                 if (oldw && !strcmp(oldw->string, "unsigned")) {
  272.                     oldw->next = w->next;
  273.                     free(w);
  274.                     w = oldw;
  275.                 }
  276.                 strcpy(w->string, "int");
  277.             }
  278.             else if ( !strcmp(w->string, "float") &&
  279.                   List_len(w->next) < 2 )
  280.             {
  281.                 strcpy(w->string, "double");
  282.             }
  283.         }
  284.         w = w->next;
  285.     }
  286. }
  287.  
  288. /* read a character: if it's a newline, increment the line count */
  289.  
  290. #ifdef __GNUC__    /* ++jrb */
  291. inline
  292. #endif
  293. int ngetc(h)
  294.     HFILE *h;
  295. {
  296.     register int c;
  297.  
  298.     c = hgetc(h);
  299.     if (c == '\n') linenum++;
  300.  
  301.     return c;
  302. }
  303.  
  304. /* read the next character from the file. If the character is '\' then
  305.  * read and skip the next character. Any comment sequence is converted
  306.  * to a blank.
  307.  */
  308.  
  309. int hnextch(h)
  310.     HFILE *h;
  311. {
  312.     int c, lastc, incomment;
  313.  
  314.     c = ngetc(h);
  315.     while (c == '\\') {
  316. DEBUG("hnextch: in backslash loop\n");
  317.         c = ngetc(h);    /* skip a character */
  318.         c = ngetc(h);
  319.     }
  320.     if (c == '/' && !inquote) {
  321.         c = ngetc(h);
  322.         if (c == '*') {
  323.             incomment = 1;
  324.             c = ' ';
  325. DEBUG("hnextch: comment seen\n");
  326.             while (incomment) {
  327.                 lastc = c;
  328.                 c = ngetc(h);
  329.                 if (lastc == '*' && c == '/')
  330.                     incomment = 0;
  331.                 else if (c < 0)
  332.                     return c;
  333.             }
  334.             return hnextch(h);
  335.         }
  336.         else {
  337. /* if we pre-fetched a linefeed, remember to adjust the line number */
  338.             if (c == '\n') linenum--;
  339.             hungetc(c, h);
  340.             return '/';
  341.         }
  342.     }
  343.     return c;
  344. }
  345.  
  346.  
  347. /* Get the next "interesting" character. Comments are skipped, and strings
  348.  * are converted to "0". Also, if a line starts with "#" it is skipped.
  349.  */
  350.  
  351. int nextch(h)
  352.     HFILE *h;
  353. {
  354.     int c, n;
  355.     char *p, numbuf[10];
  356.  
  357.     c = hnextch(h);
  358.  
  359. /* skip preprocessor directives */
  360. /* EXCEPTION: #line nnn or #nnn lines are interpreted */
  361.  
  362.     if (newline_seen && c == '#') {
  363. /* skip blanks */
  364.         do {
  365.             c = hnextch(h);
  366.         } while ( c >= 0 && (c == '\t' || c == ' ') );
  367. /* check for #line */
  368.         if (c == 'l') {
  369.             c = hnextch(h);
  370.             if (c != 'i')    /* not a #line directive */
  371.                 goto skip_rest_of_line;
  372.             do {
  373.                 c = hnextch(h);
  374.             } while (c >= 0 && c != '\n' && !isdigit(c));
  375.         }
  376.  
  377. /* if we have a digit it's a line number, from the preprocessor */
  378.         if (c >= 0 && isdigit(c)) {
  379.             p = numbuf;
  380.             for (n = 8; n >= 0; --n) {
  381.                 *p++ = c;
  382.                 c = hnextch(h);
  383.                 if (c <= 0 || !isdigit(c))
  384.                     break;
  385.             }
  386.             *p = 0;
  387.             linenum = atol(numbuf) - 1;
  388.         }
  389.  
  390. /* skip the rest of the line */
  391. skip_rest_of_line:
  392.         while (c >= 0 && c != '\n')
  393.             c = hnextch(h);
  394.         if (c < 0)
  395.             return c;
  396.     }
  397.     newline_seen = (c == '\n');
  398.  
  399.     if (c == '\'' || c == '\"') {
  400. DEBUG("nextch: in a quote\n");
  401.         inquote = c;
  402.         while ( (c = hnextch(h)) >= 0 ) {
  403.             if (c == inquote) {
  404.                 inquote = 0;
  405. DEBUG("nextch: out of quote\n");
  406.                 return '0';
  407.             }
  408.         }
  409. DEBUG("nextch: EOF in a quote\n");
  410.     }
  411.     return c;
  412. }
  413.  
  414. /*
  415.  * Get the next symbol from the file, skipping blanks.
  416.  * Return 0 if OK, -1 for EOF.
  417.  * Also collapses everything between { and }
  418.  */
  419.  
  420. int
  421. getsym(buf, h)
  422.     char *buf; HFILE *h;
  423. {
  424.     register int c;
  425.     int inbrack = 0;
  426.  
  427. DEBUG("in getsym\n");
  428.     c = glastc;
  429.     while ((c > 0) && isspace(c)) {
  430.         c = nextch(h);
  431.     }
  432. DEBUG("getsym: spaces skipped\n");
  433.     if (c < 0) {
  434. DEBUG("EOF read in getsym\n");
  435.         return -1;
  436.     }
  437.     if (c == '{') {
  438.         inbrack = 1;
  439. DEBUG("getsym: in bracket\n");
  440.         while (inbrack) {
  441.             c = nextch(h);
  442.             if (c < 0) {
  443. DEBUG("getsym: EOF seen in bracket loop\n");
  444.                 glastc = c;
  445.                 return c;
  446.             }
  447.             if (c == '{') inbrack++;
  448.             else if (c == '}') inbrack--;
  449.         }
  450.         strcpy(buf, "{}");
  451.         glastc = nextch(h);
  452. DEBUG("getsym: out of in bracket loop\n");
  453.         return 0;
  454.     }
  455.     if (!ISCSYM(c)) {
  456.         *buf++ = c;
  457.         *buf = 0;
  458.         glastc = nextch(h);
  459. DEBUG("getsym: returning special symbol\n");
  460.         return 0;
  461.     }
  462.     while (ISCSYM(c)) {
  463.         *buf++ = c;
  464.         c = nextch(h);
  465.     }
  466.     *buf = 0;
  467.     glastc = c;
  468. DEBUG("getsym: returning word\n");
  469.     return 0;
  470. }
  471.  
  472. /*
  473.  * skipit: skip until a ";" or the end of a function declaration is seen
  474.  */
  475. int skipit(buf, h)
  476.     char *buf;
  477.     HFILE *h;
  478. {
  479.     int i;
  480.  
  481.     do {
  482. DEBUG("in skipit loop\n");
  483.         i = getsym(buf, h);
  484.         if (i < 0) return i;
  485.     } while (*buf != ';' && *buf != '{');
  486.  
  487.     return 0;
  488. }
  489.  
  490. /*
  491.  * find most common type specifiers for purpose of ruling them out as
  492.  * parm names
  493.  */
  494.  
  495. int is_type_word(s)
  496. char *s;
  497. {
  498. #if 0
  499.     static char *typewords[] = {
  500.     "char",        "const",    "double",    "enum",
  501.     "float",    "int",        "long",        "short",
  502.     "signed",    "struct",    "union",    "unsigned",
  503.     "void",        "volatile",    (char *)0
  504.     };
  505. #endif
  506.     register char **ss;
  507.  
  508.     for (ss = typewords; *ss; ++ss)
  509.     if (strcmp(s, *ss) == 0)
  510.         return 1;
  511.  
  512.     return 0;
  513. }
  514.  
  515.  
  516. /* Ad-hoc macro to recognize parameter name for purposes of removal.
  517.  * Idea is to remove the bulk of easily recognized parm names without
  518.  * losing too many type specifiers. (sg)
  519.  */
  520. #define IS_PARM_NAME(w) \
  521.     (ISCSYM(*(w)->string) && !is_type_word((w)->string) && \
  522.     (!(w)->next || *(w)->next->string == ',' || \
  523.      *(w)->next->string == '['))
  524.  
  525.  
  526. /*
  527.  * given a list representing a type and a variable name, extract just
  528.  * the base type, e.g. "struct word *x" would yield "struct word"
  529.  */
  530.  
  531. Word *typelist(p)
  532.     Word *p;
  533. {
  534.     Word *w, *r;
  535.  
  536.     r = w = word_alloc("");
  537.     while (p && p->next) {
  538. /* handle int *x --> int */
  539.         if (p->string[0] && !ISCSYM(p->string[0]))
  540.             break;
  541. /* handle int x[] --> int */
  542.         if (p->next->string[0] == '[')
  543.             break;
  544.         w->next = word_alloc(p->string);
  545.         w = w->next;
  546.         p = p->next;
  547.     }
  548.     return r;
  549. }
  550.  
  551. /*
  552.  * Get a parameter list; when this is called the next symbol in line
  553.  * should be the first thing in the list.
  554.  */
  555.  
  556. Word *getparamlist(h)
  557.     HFILE *h;
  558. {
  559.     static Word *pname[MAXPARAM]; /* parameter names */
  560.     Word    *tlist,          /* type name */
  561.         *plist;          /* temporary */
  562.     int      np = 0;          /* number of parameters */
  563.     int      typed[MAXPARAM];  /* parameter has been given a type */
  564.     int    tlistdone;      /* finished finding the type name */
  565.     int    sawsomething;
  566.     int      i;
  567.     int    inparen = 0;
  568.     char buf[80];
  569.  
  570. DEBUG("in getparamlist\n");
  571.     for (i = 0; i < MAXPARAM; i++)
  572.         typed[i] = 0;
  573.  
  574.     plist = word_alloc("");
  575.  
  576. /* first, get the stuff inside brackets (if anything) */
  577.  
  578.     sawsomething = 0;    /* gets set nonzero when we see an arg */
  579.     for (;;) {
  580.         if (getsym(buf, h) < 0) return NULL;
  581.         if (*buf == ')' && (--inparen < 0)) {
  582.             if (sawsomething) {    /* if we've seen an arg */
  583.                 pname[np] = plist;
  584.                 plist = word_alloc("");
  585.                 np++;
  586.             }
  587.             break;
  588.         }
  589.         if (*buf == ';') {    /* something weird */
  590.             return ABORTED;
  591.         }
  592.         sawsomething = 1;    /* there's something in the arg. list */
  593.         if (*buf == ',' && inparen == 0) {
  594.             pname[np] = plist;
  595.             plist = word_alloc("");
  596.             np++;
  597.         }
  598.         else {
  599.             addword(plist, buf);
  600.             if (*buf == '(') inparen++;
  601.         }
  602.     }
  603.  
  604. /* next, get the declarations after the function header */
  605.  
  606.     inparen = 0;
  607.  
  608.     tlist = word_alloc("");
  609.     plist = word_alloc("");
  610.     tlistdone = 0;
  611.     sawsomething = 0;
  612.     for(;;) {
  613.         if (getsym(buf, h) < 0) return NULL;
  614.  
  615. /* handle a list like "int x,y,z" */
  616.         if (*buf == ',' && !inparen) {
  617.             if (!sawsomething)
  618.                 return NULL;
  619.             for (i = 0; i < np; i++) {
  620.                 if (!typed[i] && foundin(plist, pname[i])) {
  621.                     typed[i] = 1;
  622.                     word_free(pname[i]);
  623.                     pname[i] = word_append(tlist, plist);
  624.                 /* promote types */
  625.                     typefixhack(pname[i]);
  626.                     break;
  627.                 }
  628.             }
  629.             if (!tlistdone) {
  630.                 tlist = typelist(plist);
  631.                 tlistdone = 1;
  632.             }
  633.             word_free(plist);
  634.             plist = word_alloc("");
  635.         }
  636. /* handle the end of a list */
  637.         else if (*buf == ';') {
  638.             if (!sawsomething)
  639.                 return ABORTED;
  640.             for (i = 0; i < np; i++) {
  641.                 if (!typed[i] && foundin(plist, pname[i])) {
  642.                     typed[i] = 1;
  643.                     word_free(pname[i]);
  644.                     pname[i] = word_append(tlist, plist);
  645.                     typefixhack(pname[i]);
  646.                     break;
  647.                 }
  648.             }
  649.             tlistdone = 0;
  650.             word_free(tlist); word_free(plist);
  651.             tlist = word_alloc("");
  652.             plist = word_alloc("");
  653.         }
  654. /* handle the  beginning of the function */
  655.         else if (!strcmp(buf, "{}")) break;
  656. /* otherwise, throw the word into the list (except for "register") */
  657.         else if (strcmp(buf, "register")) {
  658.             sawsomething = 1;
  659.             addword(plist, buf);
  660.             if (*buf == '(') inparen++;
  661.             if (*buf == ')') inparen--;
  662.         }
  663.     }
  664.  
  665. /* Now take the info we have and build a prototype list */
  666.  
  667. /* empty parameter list means "void" */
  668.     if (np == 0)
  669.         return word_alloc("void");
  670.  
  671.     plist = tlist = word_alloc("");
  672.     for (i = 0; i < np; i++) {
  673.  
  674. /* If no type provided, make it an "int" */
  675.         if ( !(pname[i]->next) ||
  676.        (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) {
  677.             addword(tlist, "int");
  678.         }
  679.         while (tlist->next) tlist = tlist->next;
  680.         tlist->next = pname[i];
  681.         if (i < np - 1)
  682.             addword(tlist, ",");
  683.     }
  684.     return plist;
  685. }
  686.  
  687. /*
  688.  * emit a function declaration. The attributes and name of the function
  689.  * are in wlist; the parameters are in plist.
  690.  */
  691.  
  692. void emit(hOut, wlist, plist, startline)
  693.     HFILE *hOut;
  694.     Word *wlist, *plist;
  695.     long  startline;
  696. {
  697.     Word *w;
  698.     int count = 0;
  699.     int needspace = 0;
  700.     int isstatic = 0;
  701.     Word    *class = 0L;        /*    class name    */
  702.     Word    **lastnext;            /*    pointer to previous word's next field    */
  703.  
  704. DEBUG("emit called\n");
  705.     if (donum)
  706.         hprintf(hOut,"/*%8ld */ ", startline);
  707.  
  708.     for (w = wlist; w; w = w->next) {
  709.         if (w->string[0]) {
  710.             count ++;
  711.             if (!strcmp(w->string, "static"))
  712.                 isstatic = 1;
  713.         }
  714.     }
  715.  
  716. /* if the -e flag was given, and it's not a static function, print "extern" */
  717.  
  718.     if (print_extern && !isstatic) {
  719.         hprintf(hOut,"extern ");
  720.     }
  721.  
  722.     if (count < 2) {
  723.         hprintf(hOut,"int");
  724.         needspace = 1;
  725.     }
  726.  
  727. /*    TCL definitions come out as "class" ":" ":" "func"    */
  728. /*    Here we strip the ":"s, save the class name for later, and retie
  729.     the linked list    -adc    */
  730.  
  731.     w = wlist;
  732.     if (w->next)        /*    don't worry about single names    */
  733.     {
  734.         lastnext = &wlist;
  735.         while (w->next && *(w->next->string) != ':')
  736.         {
  737.             lastnext = &((*lastnext)->next);
  738.             w = w->next;
  739.         }
  740.         if (*(w->next->string) == ':' && w->next->next)
  741.             if (*(w->next->next->string) == ':' && w->next->next->next)
  742.             {
  743.                 class = w;                /* save class name    */
  744.                 *lastnext = w->next->next->next;    /* close gap    */
  745.                 free(w->next->next);    /*    free memory    */
  746.                 free(w->next);
  747.             }
  748.     }
  749.     
  750. /*    Scan and print the name list    */
  751.     for (w = wlist; w; w = w->next) {
  752.         if (needspace)
  753.             hprintf(hOut," ");
  754.         hprintf(hOut,"%s", w->string);
  755.         needspace = ISCSYM(w->string[0]);
  756.     }
  757.     
  758. /*    Print the '('    */
  759.     if (use_macro)
  760.         hprintf(hOut," %s((", macro_name);
  761.     else
  762.         hprintf(hOut,"(");
  763.     needspace = 0;
  764.  
  765. /*    Print the parameters    */
  766.     for (w = plist; w; w = w->next) {
  767.         if (no_parm_names && IS_PARM_NAME(w))
  768.             continue;
  769.         if (w->string[0] == ',')
  770.             needspace = 1;
  771.         else if (w->string[0] == '[')
  772.             needspace = 0;
  773.         else
  774.         {
  775.             if (needspace)
  776.                 hprintf(hOut," ");
  777.             needspace = ISCSYM(w->string[0]);
  778.         }
  779.         hprintf(hOut,"%s", w->string);
  780.     }
  781.     if (use_macro)
  782.         hprintf(hOut,"));");
  783.     else
  784.         hprintf(hOut,");");
  785.  
  786.     /*    Print the class name - adc 3/9/91    */
  787.     if (class)
  788.     {
  789.         if (print_class)
  790.             hprintf(hOut,"\t/* %s */", class->string);
  791.         free(class);
  792.     }
  793.  
  794.     hprintf(hOut,"\n");
  795. }
  796.  
  797. /*
  798.  * get all the function declarations
  799.  */
  800.  
  801. void getdecl(h, hOut)
  802.     HFILE *h, *hOut;
  803. {
  804.     Word *plist, *wlist = NULL;
  805.     char buf[80];
  806.     int sawsomething;
  807.     long startline;        /* line where declaration started */
  808.     int oktoprint;
  809. again:
  810.     word_free(wlist);
  811.     wlist = word_alloc("");
  812.     sawsomething = 0;
  813.     oktoprint = 1;
  814.  
  815.     for(;;) {
  816. DEBUG("main getdecl loop\n");
  817.         if (getsym(buf,h) < 0) {
  818. DEBUG("EOF in getdecl loop\n");
  819.              return;
  820.         }
  821. /* try to guess when a declaration is not an external function definition */
  822.         if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
  823.             !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
  824.             !strcmp(buf, "extern")) {
  825.             skipit(buf, h);
  826.             goto again;
  827.         }
  828.         if (!dostatic && !strcmp(buf, "static")) {
  829.             oktoprint = 0;
  830.         }
  831. /* for the benefit of compilers that allow "inline" declarations */
  832.         if (!strcmp(buf, "inline") && !sawsomething)
  833.             continue;
  834.         if (!strcmp(buf, ";")) goto again;
  835.  
  836. /* A left parenthesis *might* indicate a function definition */
  837.         if (!strcmp(buf, "(")) {
  838.             startline = linenum;
  839.             if (!sawsomething || !(plist = getparamlist(h))) {
  840.                 skipit(buf, h);
  841.                 goto again;
  842.             }
  843.             if (plist == ABORTED)
  844.                 goto again;
  845.  
  846. /* It seems to have been what we wanted */
  847.             if (oktoprint)
  848.                 emit(hOut, wlist, plist, startline);
  849.             word_free(plist);
  850.             goto again;
  851.         }
  852.         addword(wlist, buf);
  853.         sawsomething = 1;
  854.     }
  855. }
  856.  
  857. /*
  858.     buildtypewords
  859.     
  860.     Think doesn't like strings in globals, so we build the typewords
  861.     array here    -adc
  862. */
  863. void buildtypewords(void)
  864. {
  865.     typewords[0] = "char";
  866.     typewords[1] = "const";
  867.     typewords[2] = "double";
  868.     typewords[3] = "enum";
  869.     typewords[4] = "float";
  870.     typewords[5] = "int";
  871.     typewords[6] = "long";
  872.     typewords[7] = "short";
  873.     typewords[8] = "signed";
  874.     typewords[9] = "struct";
  875.     typewords[10] = "union";
  876.     typewords[11] = "unsigned";
  877.     typewords[12] = "void";
  878.     typewords[13] = "volatile";
  879.     typewords[14] = (char *)0;
  880. }
  881.  
  882. /*
  883.     proto
  884.     
  885.     interface to mkptypes
  886.  
  887.     given two initialized Mac handles
  888. */
  889. int proto (Handle handIn, Handle handOut)
  890. {
  891.     HFILE *hIn, *hOut;
  892.     
  893.     /*    set globals    */
  894.     #ifdef opt_e
  895.         print_extern = 1;
  896.     #endif
  897.     #ifdef opt_n
  898.         donum = 1;
  899.     #endif
  900.     #ifdef opt_s
  901.         dostatic = 1;
  902.     #endif
  903.     #ifdef opt_x
  904.         /* no parm names, only types (sg) */
  905.         no_parm_names = 1;
  906.     #endif
  907.     #ifdef opt_z
  908.         define_macro = 0;
  909.     #endif
  910.     #ifdef opt_A
  911.         use_macro = 0;
  912.     #endif
  913.     #ifdef opt_C
  914.         print_class = 1;
  915.     #endif
  916.     
  917.     buildtypewords();
  918.     strcpy(macro_name, macro_name_string);
  919.  
  920.     if (!(hIn = hopen(handIn, "r"))) {
  921. #ifdef APP
  922.         perror("Can't open input handle");
  923. #endif
  924.         return(EXIT_FAILURE);
  925.     }
  926.     if (!(hOut = hopen(handOut, "r"))) {
  927. #ifdef APP
  928.         perror("Can't open output handle");
  929. #endif
  930.         return(EXIT_FAILURE);
  931.     }
  932.  
  933. #ifdef opt_H
  934.     hprintf(hOut, "\n/* Prototypes */\n");
  935. #endif
  936.  
  937.     if (use_macro && define_macro) 
  938.     {
  939.         hprintf(hOut, "#if defined(__STDC__) || defined(__cplusplus)\n");
  940.         hprintf(hOut, "# define %s(s) s\n", macro_name);
  941.         hprintf(hOut, "#else\n");
  942.         hprintf(hOut, "# define %s(s) ()\n", macro_name);
  943.         hprintf(hOut, "#endif\n\n");
  944.     }
  945.     
  946.     linenum = 1;
  947.     newline_seen = 1;
  948.     glastc = ' ';
  949.     getdecl(hIn,hOut);
  950.     hclose(hIn);
  951.     hclose(hOut);
  952.  
  953.     if (use_macro && define_macro) {
  954.         hprintf(hOut,"\n#undef %s\n", macro_name);    /* clean up namespace */
  955.     }
  956.     return(EXIT_SUCCESS);
  957. }
  958.